package org.linlinjava.litemall.wx.controller;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.linlinjava.litemall.core.notify.AwsNotifyService;
import org.linlinjava.litemall.core.notify.NoticeHelper;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.notify.NotifyType;
import org.linlinjava.litemall.core.notify.netty.PushService;
import org.linlinjava.litemall.core.util.*;
import org.linlinjava.litemall.core.util.bcrypt.BCryptPasswordEncoder;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.wx.annotation.LogAnno;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.constant.LitemallWXConstants;
import org.linlinjava.litemall.wx.dto.UserInfoDTO;
import org.linlinjava.litemall.wx.dto.WxAppleLoginDTO;
import org.linlinjava.litemall.wx.dto.WxLoginInfoDTO;
import org.linlinjava.litemall.wx.dto.WxLogoutDTO;
import org.linlinjava.litemall.wx.enums.RegisterTypeEnum;
import org.linlinjava.litemall.wx.service.CaptchaCodeManager;
import org.linlinjava.litemall.wx.service.UserTokenManager;
import org.linlinjava.litemall.wx.service.WxAuthSerivce;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static org.linlinjava.litemall.wx.util.WxResponseCode.*;
import static org.linlinjava.litemall.wx.util.WxResponseEnum.NOT_FIND_USER;

/**
 * wx auth控制器
 * 鉴权服务
 *
 * @author yliyun
 * @date 2022/09/14
 */
@Api(tags = "WX鉴权API")
@RestController
@RequestMapping("/wx/auth")
@Validated
public class WxAuthController {

    /**
     * 用户服务
     */
    @Autowired
    private LitemallUserService userService;

    @Autowired
    private LitemallPayCodeSerivce  payCodeSerivce;

    /**
     * 天气服务
     */
    @Autowired
    private WxMaService wxService;

    /**
     * 通知服务
     */
    @Autowired
    private NotifyService notifyService;

    /**
     * 系统消息通知
     */
    @Autowired
    private NoticeHelper noticeHelper;

    @Autowired
    private AwsNotifyService awsNotifyService;

    /**
     * 优惠券指定服务
     */
    @Autowired
    private CouponAssignService couponAssignService;

    /**
     * litemall礼品卡用户服务
     */
    @Autowired
    private LitemallGiftCardUserService litemallGiftCardUserService;

    @Autowired
    private LumierePayMemberUserService lumierePayMemberUserService;

    @Autowired
    private LumiereSubscribeUserService lumiereSubscribeUserService;

    /**
     * lumierel级别会员服务
     */
    @Autowired
    private LumierelLevelMemberService lumierelLevelMemberService;

    /**
     * litemall奖励规则服务
     */
    @Autowired
    private LitemallRewardRuleService litemallRewardRuleService;

    /**
     * litemall优惠券用户服务
     */


    @Autowired
    private LumiereCouponUserService lumiereCouponUserService;

    @Autowired
    private LumiereCouponService lumiereCouponService;

    @Autowired
    private LumiereCouponStrategyService lumiereCouponStrategyService;
    /**
     * litemall奖励规则配置服务
     */
    @Autowired
    private LitemallRewardRuleConfigService litemallRewardRuleConfigService;

    /**
     * litemall分配日志服务
     */
    @Autowired
    private LitemallDistributionLogService litemallDistributionLogService;

    /**
     * litemall分布细节服务
     */
    @Autowired
    private LitemallDistributionDetailService litemallDistributionDetailService;


    /**
     * 完整日志服务
     */
    @Autowired
    private LitemallIntegralLogService integralLogService;

    /**
     * litemall味精服务
     */
    @Autowired
    private LitemallNoticeService litemallMsgService;

    @Autowired
    private LumierePayMemberUserLogService lumierePayMemberUserLogService;

    @Autowired
    private LitemallTokenService litemallTokenService;

    @Autowired
    private WxAuthSerivce wxAuthSerivce;

    /**
     * 推动服务
     */
    @Autowired
    private PushService pushService;


    @Autowired
    private LitemallIntegralLogService litemallIntegralLogService;


    @ApiOperation("登陆-「苹果登陆」")
    @PostMapping("/appleLogin")
    @LogAnno
    public Object appleLogin(@RequestBody WxAppleLoginDTO wxAppleLoginDTO, HttpServletRequest request){
        return wxAuthSerivce.appleLogin(wxAppleLoginDTO,request);
    }


    /**
     * 登录
     * 账号登录
     *
     * @param body    请求内容，{ username: xxx, password: xxx }
     * @param request 请求对象
     * @return 登录结果
     */
    @ApiOperation("登陆-「账号密码」")
    @PostMapping("login")
    @LogAnno
    public Object login(@RequestBody String body, HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username").trim();
        String password = JacksonUtil.parseString(body, "password").trim();
        String isExecute = JacksonUtil.parseString(body, "isExecute");
        //登陆的设备
        String loginIp = JacksonUtil.parseString(body, "loginIp");
        if (username == null || password == null) {
            return ResponseUtil.badArgument();
        }
        List<LitemallUser> userList = userService.list(Wrappers.lambdaQuery(LitemallUser.class)
                .eq(LitemallUser::getUsername,username)
                .eq(LitemallUser::getInnerAccount,0)
                .in(LitemallUser::getStatus,0,1,3)
        );
        LitemallUser user = null;
        if (userList.size() > 1) {
            return ResponseUtil.serious();
        } else if (userList.size() == 0) {
            Assert.isTrue(false,JSON.toJSONString(ResponseUtil.fail(AUTH_ACCOUNT_NOT_EXIST, "账号不存在")));
            //return ResponseUtil.fail(AUTH_ACCOUNT_NOT_EXIST, "账号不存在");
        } else {
            user = userList.get(0);
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        Assert.isFalse(!encoder.matches(password, user.getPassword()),JSON.toJSONString(ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号密码不对")));
        /*if (!encoder.matches(password, user.getPassword())) {
            return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号密码不对");
        }*/

        //判断他的账号状态
        Assert.isFalse(user.getStatus()==1&&!user.getDeletedBy().equals(user.getId()),JSON.toJSONString(ResponseUtil.fail(AUTH_MOBILE_UNREGISTERED, "账号已被系统禁用，请联系客服处理")));
        /*if(user.getStatus()==1&&!user.getDeletedBy().equals(user.getId())){
            return ResponseUtil.fail(AUTH_ACCOUNT_SYSTEM_DISABLE, "账号已被系统禁用，请联系客服处理");
        }*/
        //如果是用户自己注销的账号就自动解禁
        if(user.getStatus()==3&&user.getDeletedBy().equals(user.getId())){
            user.setStatus((byte) 0);
            user.setDeleted(false);
        }
        //如果没有基础会员等级就给予
        if(user.getInnerAccount()&&(user.getUserLevel()==null||user.getUserLevel()==0)){
            LumiereLevelMember lumiereLevelMember = lumierelLevelMemberService.getOne(Wrappers.lambdaQuery(LumiereLevelMember.class)
                    .isNull(LumiereLevelMember::getPid)
                    .eq(LumiereLevelMember::getDeleted, 0)
                    .eq(LumiereLevelMember::getStatus, 2));
            user.setUserLevel(lumiereLevelMember.getId().byteValue());
        }


        // 更新登录情况
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.getIpAddr(request));
        userService.updateById2(user);

        // userInfo
        UserInfoDTO userInfo = new UserInfoDTO();
        userInfo.setNickName(username);
        userInfo.setAvatarUrl(user.getAvatar());

        // token
        String token = UserTokenManager.generateToken(user.getId());
        //存储token
        LitemallToken litemallToken = LitemallToken.builder()
                .userId(user.getId()).serve(1)
                .username(username)
                .password(password)
                .device(1).validDays(720)
                .token(token).valid(0)
                .loginTime(LocalDateTime.now())
                .loginIp(loginIp)
                .generateTime(LocalDateTime.now())
                .expireTime(LocalDateTime.now().plusDays(30))
                .build();

        List<LitemallToken> litemallTokens = litemallTokenService.list(Wrappers.lambdaQuery(LitemallToken.class)
                .eq(LitemallToken::getUserId, user.getId())
                .eq(LitemallToken::getDevice,1)
                .eq(LitemallToken::getValid, 0));
        if(litemallTokens.size()>0){
            litemallTokens.stream().forEach(litemallToken1 -> litemallToken1.setValid(1));
            //有另一端登陆 「等待确认踢人下线」
            if(!Boolean.valueOf(isExecute)){
                return ResponseUtil.fail(4000,"您的账号正在另一台设备登陆！");
            }
            litemallTokenService.updateBatchById(litemallTokens);
            //发送系统通知
            noticeHelper.noticeUser(Constants.MSG_TYPE_SYSTEM,LitemallWXConstants.WX_MUTUAL_TITLE_NOTICEHELPER,LitemallWXConstants.WX_MUTUAL_NOTICEHELPER,user.getId(),user);
            //发送短信通知
            if(StrUtil.isNotBlank(user.getMobile())){
                awsNotifyService.sendSms(MOBILE_CODE_ONE+user.getMobile(),LitemallWXConstants.WX_MUTUAL_NOTICEHELPER,Constants.AWS_MESSAGE_TYPE_TRANSACTIONAL);
            }
            litemallTokenService.saveOrUpdate(litemallToken);
        }else {litemallTokenService.saveOrUpdate(litemallToken);}
        Map<Object, Object> result = new HashMap();
        result.put("token", token);
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }

    /**
     * 登录由weixin
     * 微信登录
     *
     * @param wxLoginInfo 请求内容，{ code: xxx, userInfo: xxx }
     * @param request     请求对象
     * @return 登录结果
     */
    @PostMapping("login_by_weixin")
    @LogAnno
    public Object loginByWeixin(@RequestBody WxLoginInfoDTO wxLoginInfo, HttpServletRequest request) {
        String code = wxLoginInfo.getCode();
        UserInfoDTO userInfo = wxLoginInfo.getUserInfo();
        if (code == null || userInfo == null) {
            return ResponseUtil.badArgument();
        }

        String sessionKey = null;
        String openId = null;
        try {
            WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);
            sessionKey = result.getSessionKey();
            openId = result.getOpenid();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (sessionKey == null || openId == null) {
            return ResponseUtil.fail();
        }

        LitemallUser user = userService.queryByOid(openId);
        if (user == null) {
            user = new LitemallUser();
            String membershipNumber = IdUtil.objectId();
            user.setMembershipNumber(membershipNumber.substring(0,8));
            user.setUsername(openId);
            user.setPassword(openId);
            user.setWeixinOpenid(openId);
            user.setAvatar(userInfo.getAvatarUrl());
            user.setNickname(userInfo.getNickName());
            user.setGender(userInfo.getGender());
            user.setUserLevel((byte) 0);
            user.setStatus((byte) 0);
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(IpUtil.getIpAddr(request));
            user.setSessionKey(sessionKey);

            //设置会员等级为最基本会员
            List<LumiereLevelMember> members = lumierelLevelMemberService.list(new LumiereLevelMemberExample());

            members = members.stream().filter(member -> {
                if (member.getPid().equals(null)) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());

            user.setUserLevel(members.get(0).getId().byteValue());

            userService.add(user);
            LitemallUser innerUser = new LitemallUser();
            BeanUtils.copyProperties(user,innerUser);
            innerUser.setInnerAccount(true);
            userService.add(innerUser);

            // 新用户发送注册优惠券
            couponAssignService.assignForRegister(user.getId());
        } else {
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(IpUtil.getIpAddr(request));
            user.setSessionKey(sessionKey);
            if (userService.updateById(user)) {
                return ResponseUtil.updatedDataFailed();
            }
        }

        // token
        String token = UserTokenManager.generateToken(user.getId());

        Map<Object, Object> result = new HashMap<Object, Object>();
        result.put("token", token);
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }



    /**
     * 注册验证码
     * 请求注册验证码
     * <p>
     * TODO 这里需要一定机制防止短信验证码被滥用
     *
     * @param body 手机号码 { mobile }
     * @return {@link Object}
     */
    @PostMapping("regCaptcha")
    @LogAnno
    public Object registerCaptcha(@RequestBody String body) {
        String username = JacksonUtil.parseString(body, "username");
        if (StringUtils.isEmpty(username)) {
            return ResponseUtil.badArgument();
        }
        if (!RegexUtil.isMobileValid(username) && !RegexUtil.isEmailExact(username)) {
            return ResponseUtil.fail(EMAIL_OR_MOBILE_ERROR,"邮箱或手机号不正确");
        }

        if (RegexUtil.isMobileValid(username)) {
            if (!notifyService.isSmsEnable()) {
                return ResponseUtil.fail(AUTH_CAPTCHA_UNSUPPORT, "后台验证码服务不支持");
            }
            String code = CharUtil.getRandomNum(6);
            notifyService.notifySmsTemplate(MOBILE_CODE_ONE+username, NotifyType.CAPTCHA, new String[]{code});

            boolean successful = CaptchaCodeManager.addToCache(username+"1", code);
            if (!successful) {
                return ResponseUtil.fail(AUTH_CAPTCHA_FREQUENCY, "验证码未超时10分钟，不能发送");
            }
        } else if (RegexUtil.isEmailExact(username)) {
            if (!notifyService.isMailEnable()) {
                return ResponseUtil.fail(AUTH_CAPTCHA_UNSUPPORT, "邮件发送后台验证码服务不支持");
            }
            String code = CharUtil.getRandomNum(6);
//            String tmplate = "欢迎注册Lumiere。你的注册码为%s,有效时间一分钟";
            notifyService.notifyMailTemplate("Lumiere Cafe Account Verification", NotifyType.CAPTCHA, username, new String[]{code});

            boolean successful = CaptchaCodeManager.addToCache(username+"1", code);
            if (!successful) {
                return ResponseUtil.fail(AUTH_CAPTCHA_FREQUENCY, "验证码未超时10分钟，不能发送");
            }
        }
     return ResponseUtil.ok();
    }


    /**
     * 账号注册
     */
    @PostMapping("register")
    @LogAnno
    @Transactional
    public Object register(@RequestBody String body, HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String realname = username.charAt(0) == MOBILE_CODE_ONE.charAt(0)?username.substring(1,username.length()):username;
        String password = JacksonUtil.parseString(body, "password");
        String code = JacksonUtil.parseString(body, "code").trim();
        String invitedCode = JacksonUtil.parseString(body, "invitedCode");
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            return ResponseUtil.badArgument();
        }
        if (!RegexUtil.isMobileValid(username) && !RegexUtil.isEmailExact(username)) {
            return ResponseUtil.fail(AUTH_INVALID_MOBILE, "手机号或邮箱格式不正确");
        }
        boolean userResult = userService.list(Wrappers.lambdaQuery(LitemallUser.class)
                .eq(LitemallUser::getInnerAccount,0)
                .and(wapper->{
                    wapper.eq(LitemallUser::getEmail, realname)
                    .or()
                    .eq(LitemallUser::getMobile, realname);
                })).size() > 0;
        if (userResult) {
            return ResponseUtil.fail(AUTH_NAME_REGISTERED, "用户已注册");
        }
        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(username+MOBILE_CODE_ONE);
        if (StrUtil.isEmpty(cacheCode) || !cacheCode.equals(code)) {
            return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
        }
        LitemallUser user = new LitemallUser();
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(password);
        user.setUsername(realname);
        user.setPassword(encodedPassword);
        user.setMobile(RegexUtil.isMobileValid(realname)?realname:null);
        user.setEmail(RegexUtil.isEmailExact(realname)?realname:null);
        user.setAvatar(LitemallWXConstants.LUMIEREHEAD);
        user.setNickname(realname);
        user.setGender((byte) 0);
        user.setUserLevel((byte) 0);
        user.setStatus((byte) 0);
        user.setPoints(new BigDecimal(0));
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.getIpAddr(request));

        user.setRegisterType(RegexUtil.isMobileValid(username)?RegisterTypeEnum.MOBILE.getCode():RegisterTypeEnum.EMAIL.getCode());
        //设置会员等级为最基本会员
        LumiereLevelMember lumiereLevelMember = lumierelLevelMemberService.getOne(Wrappers.lambdaQuery(LumiereLevelMember.class)
                .isNull(LumiereLevelMember::getPid)
                .eq(LumiereLevelMember::getDeleted, 0)
                .eq(LumiereLevelMember::getStatus, 2));
        user.setUserLevel(lumiereLevelMember.getId().byteValue());
        user.setUserLevel(lumiereLevelMember.getId().byteValue());


        //邀请码和被邀请码
        user.setBeenInvitedCode(invitedCode);

        String invitedStr = userService.getCharAndNum();

        List<LitemallUser> generatorCode = userService.queryUserByInvitedCode(invitedCode);

        if (generatorCode.size() == 0) {
            generatorCode = userService.queryUserByInvitedCode(invitedStr);
        }

        user.setInvitedCode(invitedStr);
        String membershipNumber = IdUtil.objectId();
        user.setMembershipNumber(membershipNumber);
        userService.add(user);
        /*LitemallUser innerUser = new LitemallUser();
        BeanUtils.copyProperties(user,innerUser);
        innerUser.setInnerAccount(true);
        userService.add(innerUser);*/

        if (!StringUtils.isEmpty(invitedCode)) {   //通过邀请码注册
            //通过邀请码查询用户
            List<LitemallUser> users = userService.queryUserByInvitedCode(invitedCode);

            if (users.size() == 0) {
                return ResponseUtil.fail(INVITE_CODE_ERROR, "邀请码错误");
            }


            //查询邀请码对应的用户的今日邀请记录
            Byte[] giveMethods  = {2};
            List<Byte> methods = Arrays.asList(giveMethods);

            List<LitemallRewardRule> list = litemallRewardRuleService.listNot(null, (byte)2,methods);

            for (LitemallRewardRule rewardRule : list) {
                LitemallDistributionLog registeLog = new LitemallDistributionLog();                   //注册者的统计数据
                LitemallDistributionLog inviteLog = new LitemallDistributionLog();
                if (rewardRule.getBeneficiary() == 1) {   //邀请人获益
                    LitemallDistributionLogExample example = new LitemallDistributionLogExample();
                    example.or().andDeletedEqualTo(false).andInviteDateEqualTo(LocalDate.now()).andTypeEqualTo((byte)2).andUserIdEqualTo(user.getId());
                    List<LitemallDistributionLog> logs = litemallDistributionLogService.list(example);

                    //注册者当天的记录
                    if (logs.size() == 0) {
                        registeLog.setUserId(user.getId());
                        registeLog.setInviteDate(LocalDate.now());
                        registeLog.setInviteNum(0);
                        registeLog.setType((byte)2);
                        registeLog.setAddTime(LocalDateTime.now());
                        registeLog.setUpdateTime(LocalDateTime.now());
                        registeLog.setRuleId(rewardRule.getId());
                        registeLog.setDeleted(false);
                        litemallDistributionLogService.add(registeLog);
                    } else {
                        inviteLog = logs.get(0);
                        inviteLog.setInviteNum(inviteLog.getInviteNum() + 1);
                        inviteLog.setUpdateTime(LocalDateTime.now());
                        litemallDistributionLogService.update(inviteLog);
                    }

                    LitemallDistributionLog finalLog = registeLog;

                    Set<Long> givenCouponIds = new HashSet<>();
                    BigDecimal givenPresentPoint = BigDecimal.ZERO;

                    List<LitemallRewardRuleConfig> litemallRewardRuleConfigs = litemallRewardRuleConfigService.listByRuleIdAndNum(rewardRule.getId(), finalLog.getInviteNum());
                    for (LitemallRewardRuleConfig litemallRewardRuleConfig : litemallRewardRuleConfigs) {
                        if (litemallRewardRuleConfig.getPresentCouponId() != null && litemallRewardRuleConfig.getPresentCouponId().length > 0) {
                            givenCouponIds.addAll(Arrays.asList(litemallRewardRuleConfig.getPresentCouponId().clone()));
                        }
                        if(litemallRewardRuleConfig.getPresentPoints() != null && litemallRewardRuleConfig.getPresentPoints().compareTo(BigDecimal.ZERO) != 0 ){
                            givenPresentPoint = givenPresentPoint.add(litemallRewardRuleConfig.getPresentPoints());
                        }
                        createDistributionDetail(givenCouponIds,givenPresentPoint,finalLog,user,user);
                    }


                    /*for (int i = 0; i < list.size(); i++) {

                        if (list.get(i).getBeneficiary() == 2) {
                            //匹配规则下是否匹配到数量
                            List<LitemallRewardRuleConfig> configs = litemallRewardRuleConfigService.listByRuleIdAndNum(list.get(i).getId(), finalLog.getInviteNum());

                            if (configs.size() != 0) {
                                if (configs.get(0).getPresentCouponId() != null && configs.get(0).getPresentCouponId().length > 0) {
                                    givenCouponIds.addAll(Arrays.asList(configs.get(0).getPresentCouponId().clone()));
                                }
                                if(configs.get(0).getPresentPoints() != null && configs.get(0).getPresentPoints().compareTo(BigDecimal.ZERO) != 0 ){
                                    givenPresentPoint = givenPresentPoint.add(configs.get(0).getPresentPoints());
                                }
                            }
                        }
                    }

                    createDistributionDetail(givenCouponIds,givenPresentPoint,finalLog,user,user);*/
                }

                if (rewardRule.getBeneficiary() == 2) {   //受邀请人获益
                    LitemallDistributionLogExample example = new LitemallDistributionLogExample();
                    example.or().andDeletedEqualTo(false).andInviteDateEqualTo(LocalDate.now()).andTypeEqualTo((byte)2).andUserIdEqualTo(users.get(0).getId());
                    List<LitemallDistributionLog> logs = litemallDistributionLogService.list(example);

                    if (logs.size() == 0) {
                        inviteLog.setUserId(users.get(0).getId());
                        inviteLog.setInviteDate(LocalDate.now());
                        inviteLog.setInviteNum(1);
                        inviteLog.setType((byte)2);
                        inviteLog.setAddTime(LocalDateTime.now());
                        inviteLog.setUpdateTime(LocalDateTime.now());
                        inviteLog.setRuleId(rewardRule.getId());
                        inviteLog.setDeleted(false);
                        litemallDistributionLogService.add(inviteLog);
                    } else {
                        inviteLog = logs.get(0);
                        inviteLog.setInviteNum(inviteLog.getInviteNum() + 1);
                        inviteLog.setUpdateTime(LocalDateTime.now());
                        litemallDistributionLogService.update(inviteLog);
                    }

                    LitemallDistributionLog finalLog = inviteLog;

                    Set<Long> givenCouponIds = new HashSet<>();
                    BigDecimal givenPresentPoint = BigDecimal.ZERO;

                    List<LitemallRewardRuleConfig> litemallRewardRuleConfigs = litemallRewardRuleConfigService.listByRuleIdAndNum(rewardRule.getId(), finalLog.getInviteNum());
                    for (LitemallRewardRuleConfig litemallRewardRuleConfig : litemallRewardRuleConfigs) {
                        if (litemallRewardRuleConfig.getPresentCouponId() != null && litemallRewardRuleConfig.getPresentCouponId().length > 0) {
                            givenCouponIds.addAll(Arrays.asList(litemallRewardRuleConfig.getPresentCouponId().clone()));
                        }
                        if(litemallRewardRuleConfig.getPresentPoints() != null && litemallRewardRuleConfig.getPresentPoints().compareTo(BigDecimal.ZERO) != 0 ){
                            givenPresentPoint = givenPresentPoint.add(litemallRewardRuleConfig.getPresentPoints());
                        }
                        createDistributionDetail(givenCouponIds,givenPresentPoint,finalLog,user,user);
                    }

                    /*for (int i = 0; i < list.size(); i++) {

                        if (list.get(i).getBeneficiary() == 1) {
                            List<LitemallRewardRuleConfig> configs = litemallRewardRuleConfigService.listByRuleIdAndNum(list.get(i).getId(), finalLog.getInviteNum() == 0 ? finalLog.getInviteNum() + 1 : finalLog.getInviteNum());

                            if (configs.size() != 0) {
                                if (configs.get(0).getPresentCouponId() != null && configs.get(0).getPresentCouponId().length > 0) {
                                    givenCouponIds.addAll(Arrays.asList(configs.get(0).getPresentCouponId().clone()));
                                }

                                if(configs.get(0).getPresentPoints() != null && configs.get(0).getPresentPoints().compareTo(BigDecimal.ZERO) != 0 ){
                                    givenPresentPoint = givenPresentPoint.add(configs.get(0).getPresentPoints());
                                }
                            }
                        }
                    }
                    createDistributionDetail(givenCouponIds,givenPresentPoint,finalLog,users.get(0),user);*/
                }
            }



            //应该插入或者更新注册者的数据还是邀请者的数据
            /*boolean registerFlag = false;
            boolean inviteFlag = false;
            LitemallDistributionLog registeLog = new LitemallDistributionLog();                   //注册者的统计数据
            LitemallDistributionLog inviteLog = new LitemallDistributionLog();
            //遍历rule表，查看已上架的rule
            for (LitemallRewardRule rewardRule : list) {
                if (rewardRule.getBeneficiary() == 1) {   //邀请人获益
                    inviteFlag = true;
                }

                if (rewardRule.getBeneficiary() == 2) {   //受邀请人获益
                    registerFlag = true;
                }
            }



            if (registerFlag == true) {
                LitemallDistributionLogExample example = new LitemallDistributionLogExample();
                example.or().andDeletedEqualTo(false).andInviteDateEqualTo(LocalDate.now()).andTypeEqualTo((byte)2).andUserIdEqualTo(user.getId());
                List<LitemallDistributionLog> logs = litemallDistributionLogService.list(example);

                //注册者当天的记录
                if (logs.size() == 0) {
                    registeLog.setUserId(user.getId());
                    registeLog.setInviteDate(LocalDate.now());
                    registeLog.setInviteNum(0);
                    registeLog.setType((byte)2);
                    registeLog.setAddTime(LocalDateTime.now());
                    registeLog.setUpdateTime(LocalDateTime.now());
                    registeLog.setDeleted(false);
                    litemallDistributionLogService.add(registeLog);
                }

                LitemallDistributionLog finalLog = registeLog;

                Set<Long> givenCouponIds = new HashSet<>();
                BigDecimal givenPresentPoint = BigDecimal.ZERO;

                for (int i = 0; i < list.size(); i++) {

                    if (list.get(i).getBeneficiary() == 2) {
                        //匹配规则下是否匹配到数量
                        List<LitemallRewardRuleConfig> configs = litemallRewardRuleConfigService.listByRuleIdAndNum(list.get(i).getId(), finalLog.getInviteNum());

                        if (configs.size() != 0) {
                            if (configs.get(0).getPresentCouponId() != null && configs.get(0).getPresentCouponId().length > 0) {
                                givenCouponIds.addAll(Arrays.asList(configs.get(0).getPresentCouponId().clone()));
                            }
                            if(configs.get(0).getPresentPoints() != null && configs.get(0).getPresentPoints().compareTo(BigDecimal.ZERO) != 0 ){
                                givenPresentPoint = givenPresentPoint.add(configs.get(0).getPresentPoints());
                            }
                        }
                    }
                }

                createDistributionDetail(givenCouponIds,givenPresentPoint,finalLog,user,user);
            }

            if (inviteFlag == true) {     //邀请者的统计数据
                LitemallDistributionLogExample example = new LitemallDistributionLogExample();
                example.or().andDeletedEqualTo(false).andInviteDateEqualTo(LocalDate.now()).andTypeEqualTo((byte)2).andUserIdEqualTo(users.get(0).getId());
                List<LitemallDistributionLog> logs = litemallDistributionLogService.list(example);

                if (logs.size() == 0) {
                    inviteLog.setUserId(users.get(0).getId());
                    inviteLog.setInviteDate(LocalDate.now());
                    inviteLog.setInviteNum(1);
                    inviteLog.setType((byte)2);
                    inviteLog.setAddTime(LocalDateTime.now());
                    inviteLog.setUpdateTime(LocalDateTime.now());
                    inviteLog.setDeleted(false);
                    litemallDistributionLogService.add(inviteLog);
                } else {
                    inviteLog = logs.get(0);
                    inviteLog.setInviteNum(inviteLog.getInviteNum() + 1);
                    inviteLog.setUpdateTime(LocalDateTime.now());
                    litemallDistributionLogService.update(inviteLog);
                }

                LitemallDistributionLog finalLog = inviteLog;

                Set<Long> givenCouponIds = new HashSet<>();
                BigDecimal givenPresentPoint = BigDecimal.ZERO;

                for (int i = 0; i < list.size(); i++) {

                    if (list.get(i).getBeneficiary() == 1) {
                        List<LitemallRewardRuleConfig> configs = litemallRewardRuleConfigService.listByRuleIdAndNum(list.get(i).getId(), finalLog.getInviteNum() == 0 ? finalLog.getInviteNum() + 1 : finalLog.getInviteNum());

                        if (configs.size() != 0) {
                            if (configs.get(0).getPresentCouponId() != null && configs.get(0).getPresentCouponId().length > 0) {
                                givenCouponIds.addAll(Arrays.asList(configs.get(0).getPresentCouponId().clone()));
                            }

                            if(configs.get(0).getPresentPoints() != null && configs.get(0).getPresentPoints().compareTo(BigDecimal.ZERO) != 0 ){
                                givenPresentPoint = givenPresentPoint.add(configs.get(0).getPresentPoints());
                            }
                        }
                    }
                }
                createDistributionDetail(givenCouponIds,givenPresentPoint,finalLog,users.get(0),user);
            }*/
        }

        //查看是否有注册邮箱对应的礼物卡
        CompletableFuture.runAsync(()->{
            List<LitemallGiftCardUser> cardUsers = litemallGiftCardUserService.findCardUserByUserName(username);
            if(cardUsers == null){
                cardUsers = litemallGiftCardUserService.findCardUserByUserName(username);
                cardUsers.get(0).setUserId(user.getId());
                litemallGiftCardUserService.updateById(cardUsers.get(0));
            }
        });
        //查看是否有待领取的优惠券
        CompletableFuture.runAsync(()->{
            List<LumiereCouponUser> litemallCouponUsers = lumiereCouponUserService.list(Wrappers.lambdaQuery(LumiereCouponUser.class)
                    .isNull(LumiereCouponUser::getUserId)
                    .eq(LumiereCouponUser::getUserName, username));
            litemallCouponUsers.stream().forEach(litemallCouponUser -> {
                litemallCouponUser.setUserId(user.getId());
            });
            lumiereCouponUserService.updateBatchById(litemallCouponUsers);
        });

        //绑定付费会员被赠送记录
        CompletableFuture.runAsync(()->{
            List<LumierePayMemberUserLog> lumierePayMemberUserLogs = lumierePayMemberUserLogService.list(Wrappers.lambdaQuery(LumierePayMemberUserLog.class)
                    .eq(LumierePayMemberUserLog::getPurchaseName, username)
                    .and(wapper->{
                        wapper.eq(LumierePayMemberUserLog::getUserId, 0)
                              .or()
                              .isNull(LumierePayMemberUserLog::getUserId);

                    }));
            lumierePayMemberUserLogs.stream().forEach(lumierePayMemberUserLog -> {
                lumierePayMemberUserLog.setUserId(user.getId());
            });
            lumierePayMemberUserLogService.updateBatchById(lumierePayMemberUserLogs);
        });


        //将别人赠送的礼物卡、订阅、会员等绑定该账号
        CompletableFuture.runAsync(()->{
            List<LitemallGiftCardUser> cardUserByUserName = litemallGiftCardUserService.findCardUserByUserName(username);
            if(CollUtil.isNotEmpty(cardUserByUserName)){
                cardUserByUserName.stream().forEach(litemallGiftCardUser -> {
                    //绑定上账号
                    litemallGiftCardUser.setUserId(user.getId());
                    litemallGiftCardUserService.updateById2(litemallGiftCardUser);
                });
            }
        });
        CompletableFuture.runAsync(()->{
            List<LumierePayMemberUser> lumierePayMemberUserList = lumierePayMemberUserService.list(Wrappers.lambdaQuery(LumierePayMemberUser.class)
                    .eq(LumierePayMemberUser::getUserName, username)
            );
            if(CollUtil.isNotEmpty(lumierePayMemberUserList)){
                lumierePayMemberUserList.stream().forEach(lumierePayMemberUser -> {
                    lumierePayMemberUser.setUserId(user.getId());
                    lumierePayMemberUserService.update(lumierePayMemberUser);
                });
            }
        });
        CompletableFuture.runAsync(()->{
            List<LumiereSubscribeUser> lumiereSubscribeUserList = lumiereSubscribeUserService.list(Wrappers.lambdaQuery(LumiereSubscribeUser.class)
                    .eq(LumiereSubscribeUser::getUserName, username)
            );
            if(CollUtil.isNotEmpty(lumiereSubscribeUserList)){
                lumiereSubscribeUserList.stream().forEach(lumiereSubscribeUser -> {
                    lumiereSubscribeUser.setUserId(user.getId());
                    lumiereSubscribeUserService.update(Wrappers.lambdaUpdate(LumiereSubscribeUser.class)
                            .eq(LumiereSubscribeUser::getId,lumiereSubscribeUser.getId())
                            .set(LumiereSubscribeUser::getUserId,user.getId())
                    );
                });
            }
        });
        //发送新人欢迎消息
        noticeHelper.noticeUser(Constants.MSG_TYPE_SYSTEM,LitemallWXConstants.WX_NEWCOMER_TITLE_NOTICEMAIL,LitemallWXConstants.WX_NEWCOMER_NOTICEMAIL,user.getId(),user);

        // userInfo
        UserInfoDTO userInfo = new UserInfoDTO();
        userInfo.setNickName(username);
        userInfo.setAvatarUrl(user.getAvatar());
        // token
        String token = UserTokenManager.generateToken(user.getId());
        Map<Object, Object> result = new HashMap();
        result.put("token", token);
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }

    /**
     * 忘记密码
     *
     * @param body    身体
     * @param request 请求
     * @return {@link Object}
     *///    /**
//     * 重置密码发送验证码
//     * @param body
//     * @param request
//     * @return
//     */
    @PostMapping("forgetPassword")
    @LogAnno
    public Object forgetPassword(@RequestBody String body, HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String code = JacksonUtil.parseString(body, "code");

        if(username.startsWith(MOBILE_CODE_ONE) && RegexUtil.isMobileValid(username)){
            username = username.substring(1,username.length());
        }

        LitemallUser user =  userService.queryMobileOrEmail(username);

        if(user  == null){
            return ResponseUtil.fail(NOT_FIND_USER);
        }

        String cacheCode = CaptchaCodeManager.getCachedCaptcha(username+"2");
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
        }

        return ResponseUtil.ok();
    }


    /**
     * 重置密码
     * 重置密码发送验证码
     *
     * @param body    身体
     * @param request 请求
     * @return {@link Object}
     */
    @PostMapping("resetPassword")
    @LogAnno
    public Object resetPassword( @RequestBody String body,HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");

        if(username.startsWith(MOBILE_CODE_ONE) && RegexUtil.isMobileValid(username)){
            username = username.substring(1,username.length());
        }
        LitemallUser user =  userService.queryMobileOrEmail(username);

        if(user  == null){
            return ResponseUtil.fail(NOT_FIND_USER);
        }


        //重置密码
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(password);
        user.setPassword(encodedPassword);

        if(userService.updateById2(user)==0){
            return ResponseUtil.updatedDataFailed();
        }

        return ResponseUtil.ok();
    }

    /**
     * 手机验证码登录
     *
     * @param body    身体
     * @param request 请求
     * @return {@link Object}
     */
    @PostMapping("loginByCode")
    @LogAnno
    public Object loginByCode(@RequestBody String body,HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String code = JacksonUtil.parseString(body, "code");
        //登陆的设备
        String loginIp = JacksonUtil.parseString(body, "loginIp");
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(username+"3");
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
        }

        List<LitemallUser> users =  userService.queryByMobile(username);

        if(users.size()  == 0){
            return ResponseUtil.fail(AUTH_MOBILE_NOT_EXIST,"手机号不存在");
        }

        LitemallUser user = users.get(0);
        //如果没有基础会员等级就给予
        if(user.getInnerAccount()&&(user.getUserLevel()==null||user.getUserLevel()==0)){
            LumiereLevelMember lumiereLevelMember = lumierelLevelMemberService.getOne(Wrappers.lambdaQuery(LumiereLevelMember.class)
                    .isNull(LumiereLevelMember::getPid)
                    .eq(LumiereLevelMember::getDeleted, 0)
                    .eq(LumiereLevelMember::getStatus, 2));
            user.setUserLevel(lumiereLevelMember.getId().byteValue());
        }

        // 更新登录情况
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.getIpAddr(request));
        if (userService.updateById(user)==false) {
            return ResponseUtil.updatedDataFailed();
        }

        UserInfoDTO userInfo = new UserInfoDTO();
        userInfo.setNickName(username);
        userInfo.setAvatarUrl(user.getAvatar());

        // token
        String token = UserTokenManager.generateToken(user.getId());

        wxAuthSerivce.squeezeDown(user,token,loginIp);
        Map<Object, Object> result = new HashMap();
        result.put("token", token);
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);

    }


    /**
     * 验证码
     * 请求验证码
     * <p>
     * TODO
     * 这里需要一定机制防止短信验证码被滥用
     *
     * @param body 手机号码 { mobile: xxx, type: xxx }
     * @return {@link Object}
     */
    @PostMapping("captcha")
    @LogAnno
    public Object captcha( @RequestBody String body) {
        String type = null;
        //取出username
        String userName = JacksonUtil.parseString(body,"username");
        //取出status
        Integer status = JacksonUtil.parseInteger(body, "status");
        LitemallUser user = userService.getOne(Wrappers.lambdaQuery(LitemallUser.class)
                .eq(LitemallUser::getMobile, userName)
                .eq(LitemallUser::getInnerAccount,0)
                .or()
                .eq(LitemallUser::getEmail, userName)
                .eq(LitemallUser::getInnerAccount,0)
        );
        if(ObjectUtil.isNull(user)){
            return ResponseUtil.fail(ACCOUNT_NOT_EXIST,"账号不存在");
        }
        type=RegexUtil.isEmailExact(userName)?"email":"mobile";

        if ("email".equals(type)) {

            if (!notifyService.isMailEnable()) {
                return ResponseUtil.fail(AUTH_CAPTCHA_UNSUPPORT, "邮件发送后台验证码服务不支持");
            }
            String code = CharUtil.getRandomNum(6);
            notifyService.notifySmsTemplate(MOBILE_CODE_ONE+user.getMobile(), NotifyType.CAPTCHA, new String[]{code});

            boolean successful = CaptchaCodeManager.addToCache(user.getEmail()+status, code);
            if (!successful) {
                return ResponseUtil.fail(AUTH_CAPTCHA_FREQUENCY, "验证码未超时10分钟，不能发送");
            }
            notifyService.notifyMailTemplate("Lumiere Cafe Account Verification", NotifyType.CAPTCHA, user.getEmail(), new String[]{code});
        } else {
            if (!notifyService.isSmsEnable()) {
                return ResponseUtil.fail(AUTH_CAPTCHA_UNSUPPORT, "小程序后台验证码服务不支持");
            }
            String code = CharUtil.getRandomNum(6);
            // TODO
            // 根据type发送不同的验证码
            notifyService.notifySmsTemplate(MOBILE_CODE_ONE+user.getMobile(), NotifyType.CAPTCHA, new String[]{code});

            boolean successful = CaptchaCodeManager.addToCache(user.getMobile()+status, code);
            if (!successful) {
                return ResponseUtil.fail(AUTH_CAPTCHA_FREQUENCY, "验证码未超时10分钟，不能发送");
            }
        }
        return ResponseUtil.ok();
    }

    /**
     * 重置
     * 账号密码重置
     *
     * @param body    请求内容
     *                {
     *                password: xxx,
     *                mobile: xxx
     *                code: xxx
     *                }
     *                其中code是手机验证码，目前还不支持手机短信验证码
     * @param request 请求对象
     * @param userId  用户id
     * @return 登录结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("reset")
    @LogAnno
    public Object reset(@RequestBody String body, HttpServletRequest request, @LoginUser Integer userId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        LitemallUser user = userService.findById(userId);
        String password = JacksonUtil.parseString(body, "password");
        String email = user.getEmail();
        String mobile = user.getMobile();
        String code = JacksonUtil.parseString(body, "code");
        String type = JacksonUtil.parseString(body, "type");

        if (StringUtils.isEmpty(type) || (StringUtils.isEmpty(email) && StringUtils.isEmpty(mobile)) || StringUtils.isEmpty(code) || StringUtils.isEmpty(password)) {
            return ResponseUtil.badArgument();
        }
        if ("email".equals(type)) {
            //判断验证码是否正确
            String cacheCode = CaptchaCodeManager.getCachedCaptcha(email);
            if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code))
                return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
            if (StringUtils.isEmpty(email))
                return ResponseUtil.fail(AUTH_EMAIL_NOT_EXIST, "邮箱未绑定");

            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            String encodedPassword = encoder.encode(password);
            user.setPassword(encodedPassword);

            if (userService.updateById2(user)==0) {
                return ResponseUtil.updatedDataFailed();
            }

        } else if ("mobile".equals(type)) {
            //判断验证码是否正确
            String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
            if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code))
                return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");
            if (StringUtils.isEmpty(mobile))
                return ResponseUtil.fail(AUTH_MOBILE_NOT_EXIST, "手机号未绑定");


            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            String encodedPassword = encoder.encode(password);
            user.setPassword(encodedPassword);

            if (userService.updateById2(user)==0) {
                return ResponseUtil.updatedDataFailed();
            }
        }


        return ResponseUtil.ok();
    }

    /**
     * 重置手机
     * 账号手机号码重置
     *
     * @param body    请求内容
     *                {
     *                password: xxx,
     *                mobile: xxx
     *                code: xxx
     *                }
     *                其中code是手机验证码，目前还不支持手机短信验证码
     * @param request 请求对象
     * @param userId  用户id
     * @return 登录结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("resetPhone")
    @LogAnno
    public Object resetPhone(@LoginUser Integer userId, @RequestBody String body, HttpServletRequest request) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        String password = JacksonUtil.parseString(body, "password");
        String mobile = JacksonUtil.parseString(body, "mobile");
        String code = JacksonUtil.parseString(body, "code");

        if (mobile == null || code == null || password == null) {
            return ResponseUtil.badArgument();
        }

        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code))
            return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");

        List<LitemallUser> userList = userService.queryByMobile(mobile);
        LitemallUser user = null;
        if (userList.size() > 1) {
            return ResponseUtil.fail(AUTH_MOBILE_REGISTERED, "手机号已注册");
        }
        user = userService.findById(userId);

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(password, user.getPassword())) {
            return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号密码不对");
        }

        user.setMobile(mobile);
        if (userService.updateById2(user)==0) {
            return ResponseUtil.updatedDataFailed();
        }

        return ResponseUtil.ok();
    }

    /**
     * 重置邮件
     * 账号邮箱重置
     *
     * @param body    请求内容
     *                {
     *                password: xxx,
     *                email: xxx
     *                code: xxx
     *                }
     * @param request 请求对象
     * @param userId  用户id
     * @return 登录结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("resetEmail")
    @LogAnno
    public Object resetEmail(@LoginUser Integer userId, @RequestBody String body, HttpServletRequest request) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        String password = JacksonUtil.parseString(body, "password");
        String email = JacksonUtil.parseString(body, "email");
        String code = JacksonUtil.parseString(body, "code");

        if (email == null || code == null || password == null) {
            return ResponseUtil.badArgument();
        }

        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(email);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code))
            return ResponseUtil.fail(AUTH_CAPTCHA_UNMATCH, "验证码错误");

        List<LitemallUser> userList = userService.queryByEmail(email);
        LitemallUser user = null;
        if (userList.size() > 1) {
            return ResponseUtil.fail(AUTH_EMAIL_REGISTERED, "邮箱已注册");
        }
        user = userService.findById(userId);

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(password, user.getPassword())) {
            return ResponseUtil.fail(AUTH_INVALID_ACCOUNT, "账号密码不对");
        }

        user.setEmail(email);
        if (userService.updateById2(user)==0) {
            return ResponseUtil.updatedDataFailed();
        }

        return ResponseUtil.ok();
    }

    /**
     * 配置文件
     * 账号信息更新
     *
     * @param body    请求内容
     *                {
     *                password: xxx,
     *                mobile: xxx
     *                code: xxx
     *                }
     *                其中code是手机验证码，目前还不支持手机短信验证码
     * @param request 请求对象
     * @param userId  用户id
     * @return 登录结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("profile")
    @LogAnno
    public Object profile(@LoginUser Integer userId, @RequestBody String body, HttpServletRequest request) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        Byte gender = JacksonUtil.parseByte(body, "gender");
        String nickname = JacksonUtil.parseString(body, "nickname");
        String mobile = JacksonUtil.parseString(body, "mobile");
        String email = JacksonUtil.parseString(body, "email");
        String birthday = JacksonUtil.parseString(body,"birthday");

        LitemallUser user = userService.findById(userId);
        if(birthday != null && birthday != "" && birthday.length() == 10 ){
            DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate birthDate = LocalDate.parse(birthday, timeDtf);
            user.setBirthday(birthDate);
        }

        if (gender != null ) {
            user.setGender(gender);
        }
        if (!StringUtils.isEmpty(nickname)) {
            user.setNickname(nickname);
        }

        if(mobile != null && mobile != "" && mobile.length() > 5){
            if(!RegexUtil.isMobileValid(mobile) ){
                return ResponseUtil.fail(AUTH_INVALID_MOBILE, "手机号不正确");
            }
        }

        if(email != null  && email != "" && email.length() > 5){
            if (!RegexUtil.isEmailExact(email)) {
                return ResponseUtil.fail(AUTH_INVALID_EMAIL);
            }
        }


        if (!StringUtils.isEmpty(email)) {
            List<LitemallUser> emailUsers =  userService.queryByEmail(email);
            if(emailUsers.size() > 0 && !emailUsers.get(0).getEmail().equals(user.getEmail())){
                return ResponseUtil.fail(AUTH_EMAIL_EXIST, "邮箱已存在，不允许更改");
            }

            user.setEmail(email);
        }

        if (!StringUtils.isEmpty(mobile)) {
            List<LitemallUser> mobileUsers =  userService.queryByMobile(mobile);
            if(mobileUsers.size() > 0 && ! mobileUsers.get(0).getMobile().equals(user.getMobile())){
                return ResponseUtil.fail(AUTH_MOBILE_EXIST, "手机号已存在，不允许更改");
            }
            user.setMobile(mobile);
        }
        if (userService.updateById2(user)==0) {
            return ResponseUtil.updatedDataFailed();
        }
        //

        return ResponseUtil.ok();
    }

    /**
     * 绑定手机
     * 微信手机号码绑定
     *
     * @param userId 用户id
     * @param body   身体
     * @return {@link Object}
     */
    @PostMapping("bindPhone")
    @LogAnno
    public Object bindPhone(@LoginUser Integer userId, @RequestBody String body) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        LitemallUser user = userService.findById(userId);
        String encryptedData = JacksonUtil.parseString(body, "encryptedData");
        String iv = JacksonUtil.parseString(body, "iv");
        WxMaPhoneNumberInfo phoneNumberInfo = this.wxService.getUserService().getPhoneNoInfo(user.getSessionKey(), encryptedData, iv);
        String phone = phoneNumberInfo.getPhoneNumber();
        user.setMobile(phone);
        if (userService.updateById2(user)==0) {
            return ResponseUtil.updatedDataFailed();
        }
        return ResponseUtil.ok();
    }

    /**
     * 注销
     * @param
     * @return
     */
    @PostMapping("logout")
    @LogAnno
    public Object logout(@RequestBody WxLogoutDTO wxLogoutDTO) {
        /*LitemallToken litemallToken = litemallTokenService.getOne(Wrappers.lambdaQuery(LitemallToken.class)
                .eq(LitemallToken::getUserId,wxLogoutDTO.getUserId())
                .eq(LitemallToken::getToken,wxLogoutDTO.getToken())
                .eq(LitemallToken::getDevice, 1)
                .eq(LitemallToken::getValid, 0));
        if(ObjectUtil.isNull(litemallToken)){
            return ResponseUtil.ok();
        }
        //清除令牌
        litemallTokenService.removeById(litemallToken);*/
        //直接清除所有 同一种设备同一账号的token
        CompletableFuture.runAsync(()->{
            litemallTokenService.remove(Wrappers.lambdaUpdate(LitemallToken.class)
                    .eq(LitemallToken::getUserId,wxLogoutDTO.getUserId())
                    .eq(LitemallToken::getServe,1)
                    .eq(LitemallToken::getDevice,1));
        });
        return ResponseUtil.unlogin();
    }

    /**
     * 信息
     *
     * @param userId 用户id
     * @return {@link Object}
     */
    @GetMapping("info")
    @LogAnno
    public Object info(@LoginUser Integer userId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }

        LitemallUser user = userService.findById(userId);

        LumiereLevelMember levelMember = null;
        if (ObjectUtil.isNotNull(user)&&user.getUserLevel() != null) {
            levelMember = lumierelLevelMemberService.findById(user.getUserLevel().intValue());
        }
        Map<Object, Object> data = new HashMap();
        data.put("username",user.getUsername());
        data.put("nickName", user.getNickname());
        data.put("avatar", user.getAvatar());
        data.put("gender", user.getGender());
        data.put("mobile", user.getMobile());
        data.put("email", user.getEmail());
        data.put("userLevel", user.getUserLevel());
        data.put("levelMemberName", levelMember != null ? levelMember.getName() : null);
        data.put("amount", user.getAvailableAmount());
        data.put("points", user.getPoints().intValue());
        data.put("inviteNode", user.getInvitedCode());
        data.put("id",user.getId());
        data.put("birthday",user.getBirthday());
        data.put("membershipNumber",user.getMembershipNumber());

        //查看是否设置了支付密码
        LitemallPayCode payCode = payCodeSerivce.getOne(Wrappers.lambdaQuery(LitemallPayCode.class).eq(LitemallPayCode::getUserId, userId));
        data.put("paymentCode",ObjectUtil.isNotNull(payCode));

        List<LitemallNoticeWithBLOBs> noticeList = litemallMsgService.querySelective(userId, null, null, null, null);
        long count = noticeList.stream().filter(notice -> !notice.getMarkRead()).count();
        data.put("markReadNum",count);
        if(user.getAddTime() != null ){
            data.put("registeDate",user.getAddTime().toLocalDate());
        }
        return ResponseUtil.ok(data);
    }

    /**
     * 创建分布细节
     *
     * @param givenCouponIds    鉴于优惠券id
     * @param givenPresentPoint 鉴于目前点
     * @param finalLog          最后日志
     * @param user              用户
     * @param registerUser      注册用户
     */
    public void createDistributionDetail(Set<Long> givenCouponIds,BigDecimal givenPresentPoint,
                                         LitemallDistributionLog finalLog,LitemallUser user,LitemallUser registerUser){
        //
        if (givenCouponIds.size() > 0 || givenPresentPoint.compareTo(BigDecimal.ZERO) > 0) {
            LitemallDistributionDetail detail = new LitemallDistributionDetail();
            detail.setDisLogId(finalLog.getId());
            detail.setRegisterId(registerUser.getId());
            detail.setPresentCouponId(givenCouponIds.toArray(new Long[givenCouponIds.size()]));
            detail.setAddTime(LocalDateTime.now());
            detail.setUpdateTime(LocalDateTime.now());
            detail.setPresentPoints(givenPresentPoint);
            detail.setRegisterUsername(user.getUsername());
            detail.setDeleted(false);
            litemallDistributionDetailService.add(detail);
            //用户获得优惠券
            for (Long strategyId :detail.getPresentCouponId()) {
                LumiereCouponStrategy lumiereCouponStrategy = lumiereCouponStrategyService.findByid(strategyId.longValue());
                long nextId = IdUtil.getSnowflake(2, 2).nextId();
                LocalDateTime[] localDateTimes = AdminCouponDateUtil.calculateExpirationTime(lumiereCouponStrategy);
                //发放券
                LumiereCouponUser couponUser = LumiereCouponUser.builder()
                        .userId(user.getId())
                        .strategyId(lumiereCouponStrategy.getId())
                        .couponId(lumiereCouponStrategy.getCouponId())
                        .userName(user.getUsername())
                        .startTime(localDateTimes[0])
                        .endTime(localDateTimes[1])
                        .code(String.valueOf(nextId))
                        .addTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .deleted(false)
                        .build();
                lumiereCouponUserService.save(couponUser);
                LumiereCoupon coupon = lumiereCouponService.getById(lumiereCouponStrategy.getCouponId());
                //发送获得优惠券的系统通知
                noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,LitemallWXConstants.WX_INVITATION_USER_TITLE_NOTICEMAIL,
                        String.format(LitemallWXConstants.WX_INVITATION_USER_COUPON_NOTICEMAIL,coupon.getName()),user.getId(),user);
            }

            //注册用户获取积分
            user.setPoints(user.getPoints().add(givenPresentPoint));
            userService.updateById2(user);
            LitemallIntegralLog l = new LitemallIntegralLog();
            l.setUserId(user.getId());
            l.setType(Constants.INTEGRAL_LOG_TYPE_ADD);
            l.setPoints(user.getPoints());
            l.setChangePoints(givenPresentPoint);
            integralLogService.add(l);
            //发送获得积分的系统通知
            noticeHelper.noticeUser(Constants.MSG_TYPE_OTHER,LitemallWXConstants.WX_INVITATION_USER_TITLE_NOTICEMAIL,String.format(LitemallWXConstants.WX_INVITATION_USER_POINTS_NOTICEMAIL,l.getChangePoints()),user.getId(),user);
        }
    }




}
